#include "fifo.h"

#define _DI() __disable_irq()
#define _EI() __enable_irq()

/*!
 * @brief       Initialize the queue
 * @param[in]   queue: Can frame queue
 * @param[in]   can_buf: can frame struct
 * @param[in]   depth: Depth of the queue
 * @retval      None
 */
void FIFO_QueueInit(CAN_Queue_t *queue, CAN_Frame_t *can_buf, uint32_t depth)
{
    queue->front         = 0;
    queue->rear          = 0;
    queue->count         = 0;
    queue->can_frame_buf = can_buf;
    queue->depth         = depth;
}

/*!
 * @brief       Determines whether the queue is empty
 * @param[in]   queue: MSG frame queue
 * @retval      true: The queue is empty
 * @retval      false: The queue is not empty
 */
bool FIFO_QueueIsEmpty(CAN_Queue_t *queue)
{
    _DI();
    bool ret_val = false;
    if (queue->count == 0U) {
        ret_val = true;
    }
    else {}
    _EI();
    return ret_val;
}

/*!
 * @brief       Determines whether the queue is full
 * @param[in]   queue: MSG frame queue
 * @retval      true: The queue is full
 * @retval      false: The queue is not full
 */
bool FIFO_QueueIsFull(CAN_Queue_t *queue)
{
    bool ret_val = false;
    _DI();
    if (queue->count >= queue->depth) {
        ret_val = true;
    }
    else {}
    _EI();
    return ret_val;
}

/*!
 * @brief       MSG frame enqueue
 * @param[in]   queue: MSG frame queue
 * @param[in]   can_frame: msg frame struct
 * @retval      MSG frame enqueue successfully or not
 */
bool FIFO_QueuePush(CAN_Queue_t *queue, CAN_Frame_t can_frame)
{
    bool ret_val = true;
    _DI();
    /* Queue is full */
    if (queue->count >= queue->depth) {
        ret_val = false;
    }
    else {
        queue->can_frame_buf[queue->rear] = can_frame;
        queue->rear                       = (queue->rear + 1) % queue->depth;
        queue->count++;
    }
    _EI();
    return ret_val;
}

/*!
 * @brief       msg frame dequeue
 * @param[in]   queue:  msg frame queue
 * @param[in]   can_frame: msg frame struct
 * @retval       frame enqueue successfully or not
 */
bool FIFO_QueuePop(CAN_Queue_t *queue, CAN_Frame_t *can_frame)
{
    bool ret_val = true;
    _DI();
    /* Queue is empty */
    if (queue->count == 0) {
        ret_val = false;
    }
    else {
        *can_frame   = queue->can_frame_buf[queue->front];
        queue->front = (queue->front + 1) % queue->depth;
        queue->count--;
    }
    _EI();
    return ret_val;
}

/*!
 * @brief       get queue free depth
 * @param[in]   queue: MSG frame queue
 * @retval       queue free depth
 */
uint16_t FIFO_QueueGetFreeDepth(CAN_Queue_t *queue) { return (queue->depth - queue->count); }
